import 'package:efood_multivendor/controller/splash_controller.dart';
import 'package:efood_multivendor/data/model/response/cart_model.dart';
import 'package:efood_multivendor/data/repository/cart_repo.dart';
import 'package:efood_multivendor/helper/size_config.dart';
import 'package:efood_multivendor/util/map_ex.dart';
import 'package:efood_multivendor/view/base/cart_view.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';

import '../data/model/response/product_model.dart';
import '../util/dimensions.dart';

class CartController extends GetxController implements GetxService {
  final CartRepo cartRepo;

  void onInit() {
    super.onInit();
  }

  // GlobalKey<CartViewState> _myKey = GlobalKey<CartViewState>();

  CartView? _cartView;
  CartController({required this.cartRepo}) {}
  List<CartModel> _cartList = [];
  double _amount = 0.0;
  Map<int, double> _amtRest = {};
  Map<int, List<CartModel>> _cartRest = {};
  bool _isCartOpen = false;
  // double _subTotal = 0;
  int _currentCategory = 0;
  int _previousCategory = 0;
  bool _isLoading = false;
  int _currentSuggestion = 0;
  int _previousSuggestion = 0;
  double _totalAddonPrice = 0;
  List<int> _totalAddonId = [];
  int i = 0;
  int _totalItemsInCart = 0;

  CartView? get cartview => _cartView;
  List<CartModel> get cartList => _cartList;
  double get amount => _amount;
  Map<int, double> get amtRest => _amtRest;
  Map<int, List<CartModel>> get cartRest => _cartRest;
  bool get isCartOpen => _isCartOpen;
  double get subTotal => subTotal;
  int get currentCategory => _currentCategory;
  int get previousCategory => _previousCategory;
  int get currentSuggestion => _currentSuggestion;
  int get previousSuggestion => _previousSuggestion;
  double get totalAddonPRice => _totalAddonPrice;
  List<int> get totalAddonId => _totalAddonId;
  bool get isLoading => _isLoading;
  int get totalItemsInCart => _totalItemsInCart;

  double addOnCost(double? cost) {
    if (cost != null) {
      return cost;
    } else {
      return 0;
    }
  }

  double totalAddonPrice(
      double price, int id, int productId, bool isAdd, bool isEmpty) {
    if (isEmpty) {
      _totalAddonPrice = 0;
    } else {
      if (isAdd) {
        if (_totalAddonId.contains(id)) {
          _totalAddonPrice = price;
        } else {
          _totalAddonPrice = (price);
          _totalAddonId.add(id);
        }
      } else {
        if (_totalAddonId.contains(id)) {
          _totalAddonPrice -= price;
        } else {
          _totalAddonPrice -= (price);
          _totalAddonId.remove(id);
        }
      }
    }
    return _totalAddonPrice;
  }

  int getTotalQuantity({int? resId}) {
    int total = 0;
    if (resId != null) {
      _cartList.forEach((element) {
        if (element.product!.restaurantId == resId) {
          total += element.quantity;
        }
      });
      return total;
    }

    _cartList.forEach((element) {
      total += element.quantity;
    });
    return total;
  }

  void getCartData() {
    _cartList = [];
    _cartList.addAll(cartRepo.getCartList());

    _cartList.forEach((cart) {
      _amount = _amount + (cart.discountedPrice! * cart.quantity);
    });
  }

  void openCart() {
    _isCartOpen = true;

    update();
  }

  void closeCart() {
    _isCartOpen = false;

    update();
  }

  void addToCart(CartModel cartModel) {
    int? restaurantId = cartModel.product?.restaurantId;
    bool? isCampaign = cartModel.product?.isCampaign;
    bool hasCampaign = false;
    bool hasNonCampaign = false;

    print("Is Campaign" + cartModel.product!.isCampaign.toString());

    AlertDialog alert3 = AlertDialog(
      scrollable: true,
      //backgroundColor: Theme.of(context).cardColor,
      shape: RoundedRectangleBorder(
        borderRadius: BorderRadius.circular(Dimensions.RADIUS_EXTRA_LARGE),
      ),
      title: Center(
          child: Column(
        children: [
          Icon(
            Icons.info,
            size: 50,
            color: Colors.deepOrange,
          )
        ],
      )),
      content: Container(
          width: 60.w,
          height: 7.5.h,
          margin: EdgeInsets.only(bottom: 15),
          decoration: BoxDecoration(
            color: Colors.white,
            borderRadius:
                BorderRadius.circular(Dimensions.PADDING_SIZE_EXTRA_LARGE),
          ),
          child: Center(
              child: Wrap(
            children: [
              Text(
                  '${Get.find<SplashController>().configModel?.limitPerItemTip}'
                      .tr,
                  style: TextStyle(fontSize: Dimensions.fontSizeLarge),
                  textAlign: TextAlign.center,
                  softWrap: true,
                  maxLines: 4),
            ],
          ))),
    );

    AlertDialog campaignConflictAlert = AlertDialog(
      scrollable: true,
      shape: RoundedRectangleBorder(
        borderRadius: BorderRadius.circular(Dimensions.RADIUS_EXTRA_LARGE),
      ),
      title: Center(
        child: Column(
          children: [
            Icon(
              Icons.info,
              size: 50,
              color: Colors.deepOrange,
            )
          ],
        ),
      ),
      content: Container(
        width: 60.w,
        height: 7.5.h,
        margin: EdgeInsets.only(bottom: 15),
        decoration: BoxDecoration(
          color: Colors.white,
          borderRadius:
              BorderRadius.circular(Dimensions.PADDING_SIZE_EXTRA_LARGE),
        ),
        child: Center(
          child: Text(
            "You cannot add both campaign and non-campaign products in the same order.",
            style: TextStyle(fontSize: Dimensions.fontSizeLarge),
            textAlign: TextAlign.center,
            softWrap: true,
          ),
        ),
      ),
    );

    AlertDialog multipleCampaignAlert = AlertDialog(
      scrollable: true,
      shape: RoundedRectangleBorder(
        borderRadius: BorderRadius.circular(Dimensions.RADIUS_EXTRA_LARGE),
      ),
      title: Center(
        child: Column(
          children: [
            Icon(
              Icons.info,
              size: 50,
              color: Colors.deepOrange,
            )
          ],
        ),
      ),
      content: Container(
        width: 60.w,
        height: 7.5.h,
        margin: EdgeInsets.only(bottom: 15),
        decoration: BoxDecoration(
          color: Colors.white,
          borderRadius:
              BorderRadius.circular(Dimensions.PADDING_SIZE_EXTRA_LARGE),
        ),
        child: Center(
          child: Text(
            "Only one campaign product is allowed per order.",
            style: TextStyle(fontSize: Dimensions.fontSizeLarge),
            textAlign: TextAlign.center,
            softWrap: true,
          ),
        ),
      ),
    );

    hasCampaign = _cartRest[restaurantId]
            ?.any((item) => item.product?.isCampaign == true) ??
        false;
    hasNonCampaign = _cartRest[restaurantId]
            ?.any((item) => item.product?.isCampaign != true) ??
        false;

    _totalItemsInCart = _cartRest[restaurantId]
            ?.fold(0, (sum, item) => (sum ?? 0) + (item.quantity)) ??
        0;

    if (isCampaign == true && hasNonCampaign) {
      // Conflict: Campaign product cannot be added with non-campaign products
      Get.dialog(campaignConflictAlert, barrierDismissible: true);
      return;
    } else if (isCampaign != true && hasCampaign) {
      // Conflict: Non-campaign product cannot be added with campaign products
      Get.dialog(campaignConflictAlert, barrierDismissible: true);
      return;
    } else if (isCampaign == true && hasCampaign) {
      bool isSameCampaignProduct = _cartRest[restaurantId]?.any((item) =>
              item.product?.isCampaign == true &&
              item.product?.id == cartModel.product?.id) ??
          false;
      print("Is Same product");
      print(isSameCampaignProduct);

      if (!isSameCampaignProduct) {
        Get.dialog(multipleCampaignAlert, barrierDismissible: true);
        return;
      }
    }

    if (_totalItemsInCart >=
        Get.find<SplashController>().configModel!.limitPerItemValue!) {
      Get.dialog(alert3, barrierDismissible: true);
      update();
    } else {
      if (getQuantity(cartModel.product) >=
          Get.find<SplashController>().configModel!.limitPerItemValue!) {
        Get.dialog(alert3, barrierDismissible: true);
      } else {
        if (getQuantity(cartModel.product) != 0) {
          int i = getIndex(cartModel.product);
          _cartList[i].quantity = _cartList[i].quantity + 1;
        } else {
          _cartList.add(cartModel);
          _cartRest.putIfAbsent(restaurantId!, () => []).add(cartModel);
        }

        // Update the total amount
        _amount += cartModel.price!;
        _amtRest.update(
          restaurantId!,
          (value) => value + cartModel.price!,
          ifAbsent: () => cartModel.price!,
        );
        setTotalItemInCart(_cartRest[restaurantId]
                ?.fold(0, (sum, item) => (sum ?? 0) + item.quantity) ??
            0);
        cartRepo.addToCartList(_cartList);
        update();
      }
    }
  }

  void setQuantity(bool isIncrement, CartModel cart) {
    int index = _cartList.indexOf(cart);
    int ind = _cartRest[cart.product!.restaurantId]!.indexOf(cart);
    if (isIncrement) {
      _cartList[index].quantity = _cartList[index].quantity + 1;
      _amount = _amount + _cartList[index].discountedPrice!;
      _amtRest.append(cart.product!.restaurantId!,
          _cartRest[cart.product!.restaurantId]?[ind].discountedPrice);
      // _amtRest[cart.product.restaurantId] +=
      //     _cartRest[cart.product.restaurantId]![ind].discountedPrice;
    } else {
      _cartList[index].quantity = _cartList[index].quantity - 1;
      _amount = _amount - _cartList[index].discountedPrice!;
      _amtRest.append(cart.product!.restaurantId!,
          _cartRest[cart.product!.restaurantId]?[ind].discountedPrice);
      // _amtRest[cart.product.restaurantId] -=
      //     _cartRest[cart.product.restaurantId]![ind].discountedPrice;
    }
    cartRepo.addToCartList(_cartList);

    update();
  }

  void removeFromCart(CartModel cartModel, bool fromRes) {
    if (getQuantity(cartModel.product) > 1) {
      _cartList[getIndex(cartModel.product!)].quantity -= 1;
      _amount -= cartModel.price!;
      _amtRest.del(cartModel.product!.restaurantId!, cartModel.price);
      // _amtRest[cartModel.product.restaurantId] -= cartModel.price;
    } else if (getQuantity(cartModel.product) == 1) {
      _cartList.removeAt(getIndex(cartModel.product));
      _amount -= cartModel.price!;

      _cartRest[cartModel.product!.restaurantId]
          ?.removeAt(getIndexRest(cartModel.product!));
      _amtRest.del(cartModel.product!.restaurantId!, cartModel.price);
      // _amtRest[cartModel.product.restaurantId] -= cartModel.price;
    }

    if (_cartList.isEmpty) {
      closeCart();
      _amount = 0;
    }
    if (fromRes) {
      if (_cartRest[cartModel.product?.restaurantId] != null &&
          _cartRest[cartModel.product?.restaurantId]?.length == 0) {
        closeCart();

        _amtRest[cartModel.product!.restaurantId!] = 0;
      }
    }
    cartRepo.addToCartList(_cartList);
    update();
  }

  void removeAddOn(int index, double price) {
    update();
  }

  void addAddon() {
    update();
  }

  void clearCartList({int? resId}) {
    if (resId != null && _cartRest[resId] != null) {
      List<int> toRemove = [];
      _cartRest[resId]?.forEach((cart) {
        toRemove.add(cart.product!.id!);

        _amount -= cart.price!;
      });
      _cartList
          .removeWhere((element) => toRemove.contains(element.product!.id));
      _cartRest[resId] = [];
      _amtRest[resId] = 0;
      _totalAddonId = [];
      _totalAddonPrice = 0;

      cartRepo.addToCartList(_cartList);
    } else {
      _cartList = [];
      _cartRest = {};
      _amtRest = {};
      _amount = 0;
      _totalAddonId = [];
      _totalAddonPrice = 0;
      cartRepo.addToCartList(_cartList);
    }

    update();
  }

  bool isExistInCart(CartModel cartModel, bool isUpdate, int cartIndex) {
    for (int index = 0; index < _cartList.length; index++) {
      if (_cartList[index].product!.id == cartModel.product!.id &&
          (_cartList[index].variation!.length > 0
              ? _cartList[index].variation![0].type ==
                  cartModel.variation![0].type
              : true)) {
        if ((isUpdate && index == cartIndex)) {
          return false;
        } else {
          return true;
        }
      }
    }
    return false;
  }

  int getIndex(Product? product) {
    for (int index = 0; index < _cartList.length; index++) {
      if (_cartList[index].product?.id == product?.id) {
        return index;
      }
    }
    return -1;
  }

  int getIndexRest(Product product) {
    bool _exist = false;
    _cartRest.forEach((key, value) {
      if (key == product.restaurantId) {
        _exist = true;
        return;
      }
    });
    if (_exist) {
      for (int index = 0;
          index < _cartRest[product.restaurantId]!.length;
          index++) {
        if (_cartRest[product.restaurantId]?[index].product?.id == product.id) {
          return index;
        }
      }
    }

    return -1;
  }

  int getQuantity(Product? product) {
    for (int index = 0; index < _cartList.length; index++) {
      if (_cartList[index].product?.id == product?.id) {
        return _cartList[index].quantity;
      }
    }
    return 0;
  }

  bool existAnotherRestaurantProduct(int restaurantID) {
    for (CartModel cartModel in _cartList) {
      if (cartModel.product?.restaurantId != restaurantID) {
        return true;
      }
    }
    return false;
  }

  void removeAllAndAddToCart(CartModel cartModel) {
    _cartList = [];
    _cartRest = {};
    _amtRest = {};
    _cartList.add(cartModel);
    _cartRest.addEntries((<int, List<CartModel>>{
      cartModel.product!.restaurantId!: [cartModel]
    }).entries);

    _amount = cartModel.price! * cartModel.quantity;
    _amtRest.addEntries((<int, double>{
      cartModel.product!.restaurantId!: cartModel.price!
    }).entries);
    cartRepo.addToCartList(_cartList);
    update();
  }

  void setCurrentCategory(int id) {
    _currentCategory = id;
    update();
  }

  void setPreviousCategory(int id) {
    _previousCategory = id;
    update();
  }

  void setCurrentSuggestion(int id) {
    _currentSuggestion = id;
    update();
  }

  void setPreviousSuggestion(int id) {
    _previousSuggestion = id;
    update();
  }

  void clearPreviousRestaurant(int? resId) {
    List<int> toRemove = [];

    if (resId != null) {
      _cartList.forEach((cart) {
        if (cart.product?.restaurantId == resId) {
          toRemove.add(cart.product!.id!);
          _amount -= cart.price!;
          _cartRest[cart.product!.restaurantId!] = [];
        }
      });

      _cartList
          .removeWhere((element) => toRemove.contains(element.product!.id));

      _amtRest.removeWhere((key, value) => key == resId);
    }
    update();
  }

  void startLoader() {
    _isLoading = true;
    update();
  }

  void stopLoader() {
    _isLoading = false;
    update();
  }

  setTotalItemInCart(int quantity) {
    _totalItemsInCart = quantity;
    update();
  }
}
